using System.Collections.Generic;
using GameFramework.Battle.Core;
using Gameplay.PVE.Data;
using Gameplay.PVE.Entity;
using Gameplay.PVE.Utils;
using UnityEngine;
using Yoozoo.Libs;
using Yoozoo.Managers;
using Yoozoo.Managers.ResourceManagerV2.Runtime;
using Yoozoo.Gameplay.RTS;

namespace Gameplay.PVE
{
    public class SearchComponent:IComponent,ITransmit
    {
        //搜索
        private UnitBase unit;
        private GameObject searchRangeObj;
        private float searchFailTime;
        void IClass.OnReset()
        {
            
        }

        void IComponent.OnInitialize(UnitBase unit)
        {
            this.unit = unit;
        }

        public void Update()
        {
            ((IComponent) this).OnUpdate();
        }
        
        public void Initialize(UnitBase unit)
        {
            ((IComponent)this).OnInitialize(unit);
        }

        public void Birth()
        {
            ((IComponent)this).OnBirth();
        }
        
        void IComponent.OnUpdate()
        {
            if (unit.Data.searchType == 3 && unit.Data.summonParent != null)
            {
                unit.Data.SetLockTarget(unit.Data.summonParent.Data.lockTarget);
            }
            if (unit.Data.lockTarget == null && !unit.Data.HasSpecificOrder())
            {
                foreach (var item in unit.Data.hatredDic.Values)
                {
                    if (!item.source.Data.isDead)
                    {
                        unit.Data.SetLockTarget(item.source);
                    }
                }
            }
        }

        void IComponent.OnBirth()
        {
            
        }

        void IComponent.OnDead()
        {
            
        }

        private void AddHatred(BattleUnit source)
        {
            int id = source.Data.id;
            /*HatredInfo info;
            if (unit.Data.hatredDic.TryGetValue(id, out info))
            {
                info.hatresTime = TimeManager.logicTime;
            }
            else
            {
                unit.Data.hatredDic.Add(id,new HatredInfo
                {
                    hatresTime = TimeManager.logicTime,
                    id = id,
                    source = source,
                });
            }*/

            if (Vector3.Distance(source.Data.position, unit.Data.position) <= 5 && source.Data.rangeType == 1)
            {
                unit.Data.hatredTarget = source;
            }
            
            CheckNeedLockHatred(source);
            if (unit.Data.lockTarget != null)
            {
                searchFailTime = 0;
            }
        }


        private void CheckNeedLockHatred(BattleUnit source)
        {
            if (unit.Data.HasSpecificOrder())
            {
                return;
            }
            
            if (unit.Data.lockTarget != null)
            {
                /*if (unit.Data.hatredDic.TryGetValue(unit.Data.lockTarget.Data.id, out var lockTarget))
                {
                    return;
                }*/

                //if (unit.Data.IsAttackInRange())
                {
                    return;
                }
            }
            if (!unit.Data.IsInAttack())
            {
                unit.Data.SetLockTarget(source);
                unit.Transmit(ETransmitType.SearchSuccess);
                
                
                if (unit.Data.team == 2)//队友检测仇恨
                {
                    var team = UnitManager.Instance.GetAllUnitByTeam(2);
                    for (int i = 0; i < team.Count; i++)
                    {
                        if (team[i].Data.stage == unit.Data.stage && team[i].Data.lockTarget == null && Vector3.Distance(team[i].Data.position,unit.Data.position) <= unit.Data.hatredDistance)
                        {
                            team[i].Data.SetLockTarget(source);
                            unit.Transmit(ETransmitType.SearchSuccess);
                        }
                    }
                }
            }
        }
        
        
        void ITransmit.OnTransmit(ETransmitType type, BaseTransmitArg arg)
        {
            if (type == ETransmitType.AutoSearch)
            {
                AutoSearch();
            }
            else if (type == ETransmitType.HatredSearch)
            {
                HatredSearchTransmitArg a = arg as HatredSearchTransmitArg;
                AddHatred(a.source);
            }
            else if (type == ETransmitType.SearchBattleInSight)
            {
                AutoSearchBattleInSight();
            }
            else if (type == ETransmitType.StageToNext)
            {
                unit.Data.hatredDic.Clear();
            }
            else if (type == ETransmitType.RpgStageToNext)
            {
                unit.Data.hatredDic.Clear();
            }
            else if (type == ETransmitType.AimSearch)
            {
                AimSearch();
            }
        }

        private void AutoSearchBattleInSight()
        {
            var units = UnitManager.Instance.GetAllUnitByTeam(0);
            for (int i = 0; i < units.Count; i++)
            {
                if (units[i].Data.IsInAttack() && CheckIsInRange(units[i].Data.position))
                {
                    unit.Data.hasBattleInSight = true;
                    unit.Data.battleInSightPosition = units[i].Data.position;
                    return;
                }
            }

            units = UnitManager.Instance.GetAllUnitByTeam(2);
            for (int i = 0; i < units.Count; i++)
            {
                if (units[i].Data.IsInAttack() && Vector3.Distance(units[i].Data.position, unit.Data.position) < unit.Data.searchRange)
                {
                    unit.Data.hasBattleInSight = true;
                    unit.Data.battleInSightPosition = units[i].Data.position;
                    return;
                }
            }
        }

        private void AimSearch()
        {
            int targetTeam = unit.Data.GetTargetTeam(unit.Data.searchType);

            var targetList = UnitManager.Instance.GetAllUnitByTeam(targetTeam);
            List<BattleUnit> candidates = new List<BattleUnit>();
            for (int i = 0; i < targetList.Count; i++)
            {
                if (CheckIsCanAimLock(targetList[i]))
                {
                    candidates.Add(targetList[i]);
                }
            }

            if (candidates.Count > 0)
            {
                candidates.Sort(SortAngle);
                unit.Data.SetLockTarget(candidates[0]);
            }
            
        }
        
        private void AutoSearch()
        {
            if (!PveManager.Instance.IsStageActive)
            {
                return;
            }

            if (unit.Data.attractAttackTarget != null)
            {
                unit.Data.SetLockTarget(unit.Data.attractAttackTarget);
            }

            if (unit.Data.searchType == 3 && unit.Data.summonParent != null)
            {
                unit.Data.SetLockTarget(unit.Data.summonParent.Data.lockTarget);
            }
            
            if (unit.Data.lockTarget != null && unit.Data.lockTarget.Data.lockTarget == unit)
            {
                return;
            }

            if (unit.Data.searchType == 2)
            {
                unit.Data.SetLockTarget(unit as BattleUnit);
                unit.Transmit(ETransmitType.SearchSuccess);
                return;
            }
           
            
            
            int targetTeam = unit.Data.GetTargetTeam(unit.Data.searchType);

            var targetList = UnitManager.Instance.GetAllUnitByTeam(targetTeam);
            List<BattleUnit> candidates = new List<BattleUnit>();
            for (int i = 0; i < targetList.Count; i++)
            {
                if (CheckIsCanLock(targetList[i]))
                {
                    candidates.Add(targetList[i]);
                }
            }
            
            if (candidates.Count > 0)
            {
                if (unit.Data.searchSort == 0)
                {
                    candidates.Sort(SortDistanceManhattan);
                }
                else if (unit.Data.searchSort == 1)
                {
                    candidates.Sort(SortDistanceMax);
                }
                else if (unit.Data.searchSort == 2)
                {
                    candidates.Sort(SortHpPercentMin);
                }
                else if (unit.Data.searchSort == 3)
                {
                    candidates.Sort(SortHpPercentMax);
                }
                else if (unit.Data.searchSort == 4)
                {
                    candidates.Sort(SortBack);
                }

                var realTarget = candidates[0] as UnitBase;
                //如果该对象在掩体中，则把目标变为掩体
                var replaceTarget = realTarget.Data.GetReplaceObstacleUnit();
                if (replaceTarget != null && replaceTarget.Data.team != unit.Data.team)
                {
                    realTarget = replaceTarget;
                }
                unit.Data.SetLockTarget(realTarget);
                unit.Transmit(ETransmitType.SearchSuccess);
            }
            else
            {
                if (unit.Data.team == 0)// && searchFailTime == 0)
                {
                    //searchFailTime = TimeManager.logicTime;
                   
                }

                //if (searchFailTime != 0 && TimeManager.logicTime - searchFailTime > 0.1f)
                {
                    //unit.Data.SetLockTarget(PveManager.Instance.GetTeamLockTarget(unit.Data.searchType));
                    //searchFailTime = 0;
                }
            }
        }

        private int SortBack(BattleUnit a, BattleUnit b)
        {
            if (a.Data.positionType == b.Data.positionType)
            {
                return Vector3.Distance(a.Data.position, unit.Data.position)
                    .CompareTo(Vector3.Distance(b.Data.position, unit.Data.position));
            }
            return b.Data.positionType.CompareTo(a.Data.positionType);
        }

        private int SortHpPercentMin(BattleUnit a, BattleUnit b)
        {
            return (a.Data.CurrentHp / a.Data.TotalHp).CompareTo(b.Data.CurrentHp / b.Data.TotalHp);
        }
        
        private int SortHpPercentMax(BattleUnit a, BattleUnit b)
        {
            return (b.Data.CurrentHp / b.Data.TotalHp).CompareTo(a.Data.CurrentHp / a.Data.TotalHp);
        }

        private int SortDistanceManhattan(BattleUnit a, BattleUnit b)
        {
            return PveUtils.GetManhattanDistance(a.Data.position,unit.Data.position).CompareTo(PveUtils.GetManhattanDistance(b.Data.position,unit.Data.position));
        }
        
        private int SortDistanceMin(BattleUnit a, BattleUnit b)
        {
            return Vector3.Distance(a.Data.position, unit.Data.position)
                .CompareTo(Vector3.Distance(b.Data.position, unit.Data.position));
        }
        
        private int SortDistanceMax(BattleUnit a, BattleUnit b)
        {
            return Vector3.Distance(b.Data.position, unit.Data.position)
                .CompareTo(Vector3.Distance(a.Data.position, unit.Data.position));
        }
        
        private int Sort(BattleUnit a, BattleUnit b)
        {
            if (unit.Data.searchType == 1)
            {
                return (a.Data.TotalHp - a.Data.CurrentHp).CompareTo(b.Data.TotalHp - b.Data.CurrentHp);
            }

            if (unit.Data.searchSort == a.Data.battleType && unit.Data.searchSort != b.Data.battleType)
            {
                return -1;
            }
            if (unit.Data.searchSort == b.Data.battleType && unit.Data.searchSort != a.Data.battleType)
            {
                return 1;
            }
            
            if (unit.Data.roadType == a.Data.roadType && unit.Data.roadType!= b.Data.roadType)
            {
                return -1;
            }

            if (unit.Data.roadType == b.Data.roadType && unit.Data.roadType != a.Data.roadType)
            {
                return 1;
            }
            return Vector3.Distance(a.Data.position, unit.Data.position)
                .CompareTo(Vector3.Distance(b.Data.position, unit.Data.position));
        }

        private int SortAngle(BattleUnit a, BattleUnit b)
        {
            float aAngle = Vector3.Angle(a.Data.position - unit.Data.position, unit.Data.manualAimForward);
            float bAngle = Vector3.Angle(b.Data.position - unit.Data.position, unit.Data.manualAimForward);
            return aAngle.CompareTo(bAngle);
        }

        private bool CheckIsCanLock(BattleUnit target)
        {
            if (target.Data.isInSpecialCase)
            {
                return false;
            }

            if (target.Data.isShowingSpawn)
            {
                return false;
            }

            if (!target.Data.selectable)
            {
                return false;
            }

            if (!target.Data.hasJoinBattle && PveManager.Instance.isInRpg)
            {
                return false;
            }

            if (!target.Data.IsInScreen())
            {
                return false;
            }

            if (unit.Data.rpgNormalAttackSkillConfig != null)
            {
                if (!PveTargetSearchHelper.CheckIsInTagList(unit, target, unit.Data.rpgNormalAttackSkillConfig))
                {
                    return false;
                }
            }
            
            if (unit.Data.searchType == 0)
            {
                return !target.Data.isDead && CheckIsInRange(target.Data.position);
            }
            else// if (unit.Data.searchType == 1)
            {
                return !target.Data.isDead && CheckIsInRange(target.Data.position);// &&
                       //target.Data.CurrentHp < target.Data.TotalHp;
            }
        }
        
        private bool CheckIsCanAimLock(BattleUnit target)
        {
            if (target.Data.isInSpecialCase)
            {
                return false;
            }

            if (target.Data.isShowingSpawn)
            {
                return false;
            }

            var isInRange = Vector3.Distance(target.Data.position, unit.Data.position) <= unit.Data.attackRange;
            return !target.Data.isDead && isInRange;

            float hpTotal;
            float shield;
            
        }

        private bool CheckIsInRange(Vector3 position)
        {
            if (PveManager.Instance.isInRpg)
            {
                if (PveManager.Instance.isEnemyStartSearch && unit.Data.team == 2)
                {
                    return true;
                }

                bool isinRange = false;
                if (unit.Data.team == 2)
                {
                    isinRange = Vector3.Distance(unit.Data.position, position) <= unit.Data.attackRange;
                    PveManager.Instance.isEnemyStartSearch = true;
                    isinRange = true;
                }
                else
                {
                    isinRange = true;//Vector3.Distance(unit.Data.position, position) <= unit.Data.attackRange;
                }
                return isinRange;
            }
            /*else
            {
                return true;
            }*/
            for (int i = 0; i < unit.Data.searchInfos.Count; i++)
            {
                if (unit.Data.searchInfos[i].searchType == 1)
                {
                    //圆形索敌
                    var searchRange = unit.Data.searchInfos[i].searchArg["Radius"];
                    return Vector3.Distance(position, unit.Data.position) <= searchRange;
                }
                else if (unit.Data.searchInfos[i].searchType == 0)
                {
                    //扇形索敌
                    float maxAngle = unit.Data.searchInfos[i].searchArg["Angle"];
                    float radius = unit.Data.searchInfos[i].searchArg["Radius"];
                    float angle = Vector3.Angle(unit.Data.forward, position - unit.Data.position);
                    float distance = Vector3.Distance(unit.Data.position, position);
                    return (angle <= maxAngle * 0.5f && distance <= radius);
                }
            }
            return false;
        }
        
        public void Dispose()
        {
            ((IClass)this).OnReset();
        }
    }
}